#include "sct/rtspserver/amrsource.h"

namespace sct
{

CAMRSource*
CAMRSource::createNew(UsageEnvironment& env, void* audio) {
//  FILE* fid = NULL;
//  Boolean magicNumberOK = True;
	uint8_t * buff = NULL;
  do {
	  CStreamSource* enc = (CStreamSource*)audio;

//	  int maxlen = 100000;
//	  buff = new uint8_t[maxlen];
//
//
//	  int ret = 0;
//	  int64_t pts = 0;
//	  int ntrunc = 0;
//	  ret = enc->getdata(buff, maxlen, &pts, &ntrunc);
//
//	  if(ret <= 0) break;
//
//	  if(ntrunc > 0)
//	  {
//		  SCT_LOG("buffer too small!!! error.");
//		  break;
//	  }

//    fid = OpenInputFile(env, fileName);
//    if (fid == NULL) break;

    // Now, having opened the input file, read the first few bytes, to
    // check the required 'magic number':
//    magicNumberOK = False; // until we learn otherwise
    Boolean isWideband = False; // by default
    unsigned numChannels = 1; // by default
//    char buf[100];
//    // Start with the first 6 bytes (the first 5 of which must be "#!AMR"):
//    if (fread(buf, 1, 6, fid) < 6) break;
//    if (strncmp(buf, "#!AMR", 5) != 0) break; // bad magic #
//    unsigned bytesRead = 6;
//
//    // The next bytes must be "\n", "-WB\n", "_MC1.0\n", or "-WB_MC1.0\n"
//    if (buf[5] == '-') {
//      // The next bytes must be "WB\n" or "WB_MC1.0\n"
//      if (fread(&buf[bytesRead], 1, 3, fid) < 3) break;
//      if (strncmp(&buf[bytesRead], "WB", 2) != 0) break; // bad magic #
//      isWideband = True;
//      bytesRead += 3;
//    }
//    if (buf[bytesRead-1] == '_') {
//      // The next bytes must be "MC1.0\n"
//      if (fread(&buf[bytesRead], 1, 6, fid) < 6) break;
//      if (strncmp(&buf[bytesRead], "MC1.0\n", 6) != 0) break; // bad magic #
//      bytesRead += 6;
//
//      // The next 4 bytes contain the number of channels:
//      char channelDesc[4];
//      if (fread(channelDesc, 1, 4, fid) < 4) break;
//      numChannels = channelDesc[3]&0xF;
//    } else if (buf[bytesRead-1] != '\n') {
//      break; // bad magic #
//    }
//
//    // If we get here, the magic number was OK:
//    magicNumberOK = True;

#ifdef DEBUG
    fprintf(stderr, "isWideband: %d, numChannels: %d\n",
	    isWideband, numChannels);
#endif
    return new CAMRSource(env, enc, isWideband, numChannels);
  } while (0);

  // An error occurred:
//  CloseInputFile(fid);
//  if (!magicNumberOK) {
//    env.setResultMsg("Bad (or nonexistent) AMR file header");
//  }
//  return NULL;

  SCT_DELETE_ARRAY(buff);
  return NULL;
}

CAMRSource
::CAMRSource(UsageEnvironment& env, CStreamSource* audio,
		     Boolean isWideband, unsigned numChannels)
  : AMRAudioSource(env, isWideband, numChannels),
    mSource(audio),mStartReadTime(0),
	mReadTask(NULL) {
}

CAMRSource::~CAMRSource() {
//  CloseInputFile(fFid);
	if(mReadTask)
	{
		envir().taskScheduler().unscheduleDelayedTask(mReadTask);
	}
}

// The mapping from the "FT" field to frame size.
// Values of 65535 are invalid.
#define FT_INVALID 65535
static unsigned short const frameSize[16] = {
  12, 13, 15, 17,
  19, 20, 26, 31,
  5, FT_INVALID, FT_INVALID, FT_INVALID,
  FT_INVALID, FT_INVALID, FT_INVALID, 0
};
static unsigned short const frameSizeWideband[16] = {
  17, 23, 32, 36,
  40, 46, 50, 58,
  60, 5, FT_INVALID, FT_INVALID,
  FT_INVALID, FT_INVALID, 0, 0
};

// Note: We should change the following to use asynchronous file reading, #####
// as we now do with ByteStreamFileSource. #####
void CAMRSource::tryToGetNextFrame(void* p) {
	CAMRSource* self = (CAMRSource*)p;
	self->mReadTask = NULL;

	if( !self->isCurrentlyAwaitingData() )
	{
		return;
	}


  // Begin by reading the 1-byte frame header (and checking it for validity)
	int ret = 0;
	int64_t pts = 0;
	int ntrunc = 0;

  while (1) {
		 ret = 0;
		 pts = 0;
		 ntrunc = 0;
		ret = self->mSource->getdata(self->fTo, self->fMaxSize, &pts, &ntrunc);

		if(ret <= 0)
		{
			if(currentTime() - self->mStartReadTime > 3)
			{
				self->handleClosure();
			}
			else
			{
				self->mReadTask = self->envir().taskScheduler().scheduleDelayedTask(50000,
							tryToGetNextFrame, self);
			}
			return;
		}

		self->fLastFrameHeader = *self->fTo;

    if ((self->fLastFrameHeader&0x83) != 0) {
#ifdef DEBUG
      fprintf(stderr, "Invalid frame header 0x%02x (padding bits (0x83) are not zero)\n", fLastFrameHeader);
#endif
    } else {
      unsigned char ft = (self->fLastFrameHeader&0x78)>>3;
      self->fFrameSize =self-> fIsWideband ? frameSizeWideband[ft] : frameSize[ft];
      if (self->fFrameSize == FT_INVALID) {
#ifdef DEBUG
	fprintf(stderr, "Invalid FT field %d (from frame header 0x%02x)\n",
		ft, fLastFrameHeader);
#endif
      } else {
	// The frame header is OK
#ifdef DEBUG
	fprintf(stderr, "Valid frame header 0x%02x -> ft %d -> frame size %d\n", fLastFrameHeader, ft, fFrameSize);
#endif
	break;
      }
    }
  }


  self->fFrameSize = ret -1;
  memmove(self->fTo, self->fTo+1, self->fFrameSize);
  self->fNumTruncatedBytes = ntrunc;

	self->fPresentationTime.tv_sec = pts / 1000000;
	self->fPresentationTime.tv_usec = pts % 1000000;

	self->fDurationInMicroseconds = 0;


	self->nextTask() = self->envir().taskScheduler().scheduleDelayedTask(0,
			(TaskFunc*)FramedSource::afterGetting, self);
 }


void CAMRSource::doGetNextFrame()
{
	if(NULL == mReadTask)
	{
		mStartReadTime = currentTime();
		mReadTask = envir().taskScheduler().scheduleDelayedTask(0,
			tryToGetNextFrame, this);
	}
	else
	{
		SCT_LOGD();
	}
}

void CAMRSource::doStopGettingFrames()
{
	if(mReadTask)
	{
		envir().taskScheduler().unscheduleDelayedTask(mReadTask);
	}
}

};
